package main

import (
	"encoding/json"
	"fmt"
	"github.com/bitly/go-simplejson"
	"os"
	"parking/src/structs"
	"strconv"
	"time"
)

const (
	gpioBasePath = "/sys/class/gpio"
)

// 处理道闸相关指令
func handleBarrierMessage(payloadJson *simplejson.Json) {
	msgId, _ := payloadJson.Get("msgId").String()
	channel, _ := payloadJson.Get("channel").String()
	pinNum, _ := strconv.Atoi(channel)
	if err := gpioOperate(pinNum); err != nil {
		// 统一错误响应
		deviceRsp := structs.NewDeviceRsp("ioOutputRsp", msgId, "error", err.Error())
		payload, _ := json.Marshal(deviceRsp)
		mqttMessage := structs.NewMQTTMessage(topicPublish_server, 0, false, payload)
		mqttSendMessageToServer(mqttMessage)
		logger.Errorf("开关闸指令执行失败,msgId: %v", msgId)
	} else {
		// 成功响应
		deviceRsp := structs.NewDeviceRsp("ioOutputRsp", msgId, "ok", "")
		payload, _ := json.Marshal(deviceRsp)
		mqttMessage := structs.NewMQTTMessage(topicPublish_server, 0, false, payload)
		mqttSendMessageToServer(mqttMessage)
		logger.Infof("开关闸指令执行成功,msgId: %v", msgId)
	}
}

// 处理道闸相关指令(离线模式)
func handleBarrierMessageInOffLineMod(payloadJson *simplejson.Json) {
	cameraId, _ := payloadJson.Get("devId").String()
	cameraInfoStruct, exists := camerasInfoMap[cameraId]
	if !exists {
		logger.Errorf("未找到 cameraId 对应的设备信息: %s", cameraId)
		return
	}
	pinNum, _ := strconv.Atoi(cameraInfoStruct.GetOpenChannel())
	if err := gpioOperate(pinNum); err != nil {
		logger.Errorf("开关闸指令(offline)执行失败,cameraId: %v", cameraId)
	} else {
		logger.Infof("开关闸指令(offlien)执行成功,cameraId: %v", cameraId)
	}

}

// 一次完整gpio操作
func gpioOperate(pinNumber int) error {

	if err := ensureExported(pinNumber); err != nil {
		logger.Errorf("GPIO初始化失败 | 阶段:导出校验")
		return err
	}

	if err := setDirection(pinNumber, "out"); err != nil {
		logger.Errorf("模式配置失败 | 阶段:方向设置")
		return err
	}

	if err := writePin(pinNumber, 1); err != nil {
		logger.Errorf("信号操作异常 | 阶段:设置通路")
		return err
	}

	time.Sleep(1 * time.Second)

	if err := writePin(pinNumber, 0); err != nil {
		logger.Errorf("信号复位失败 | 阶段:设置断路")
		return err
	}

	return nil
}

// 检查串口导出
func ensureExported(pinNumber int) error {
	gpioPath := fmt.Sprintf("%s/gpio%d", gpioBasePath, pinNumber)
	if _, err := os.Stat(gpioPath); !os.IsNotExist(err) {
		return nil
	}

	exportFile := gpioBasePath + "/export"
	f, err := os.OpenFile(exportFile, os.O_WRONLY, 0644)
	if err != nil {
		logger.Errorf("硬件接口访问异常 | 文件:%s | 错误类型:%T", exportFile, err)
		return err
	}
	defer f.Close()

	if _, err = f.WriteString(strconv.Itoa(pinNumber)); err != nil {
		logger.Errorf("硬件配置写入失败 | 内容:%d | 错误详情:%v", pinNumber, err)
		return err
	}
	return nil
}

// 设置输出方向
func setDirection(pin int, direction string) error {
	path := fmt.Sprintf("%s/gpio%d/direction", gpioBasePath, pin)
	f, err := os.OpenFile(path, os.O_WRONLY, 0644)
	if err != nil {
		logger.Errorf("配置文件打开失败 | 路径:%s | 权限需求:0644", path)
		return err
	}
	defer f.Close()

	if _, err = f.WriteString(direction); err != nil {
		logger.Errorf("硬件参数配置失败 | 方向:%s | 系统错误:%v", direction, err)
		return err
	}
	return nil
}

// 控制电平输出
func writePin(pin int, value int) error {
	path := fmt.Sprintf("%s/gpio%d/value", gpioBasePath, pin)
	// 打开电平控制文件
	f, err := os.OpenFile(path, os.O_WRONLY, 0644)
	if err != nil {
		logger.Error("电平文件打开失败 | Pin:%d | 路径:%s | 错误:%w", pin, path, err)
		return err
	}
	defer f.Close()

	// 写入电平值
	if _, err = f.WriteString(strconv.Itoa(value)); err != nil {
		logger.Error("电平值写入失败 | Pin:%d | 值:%d | 错误:%w", pin, value, err)
		return err
	}
	logger.Debugf("电平设置成功 | Pin:%d | 值:%d", pin, value)

	return nil
}
